package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.article.PublishArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.common.wemedia.WemediaConstants;
import com.heima.feigns.AdminFeign;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author huan
 * @serial 每天一百行, 致敬未来的自己
 * @Description
 */
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private AdminFeign adminFeign;
    @Value("${file.oss.web-site}")
    private String webSite;

    /**
     * TODO 自媒体文章审核
     * @param id 自媒体文章id
     */
    @Override
    public void autoScanWmNews(Integer id) {
        log.info("自动审核发布方法 被调用!!  当前审核发布的文章  id===> {}", id);
        //1. 根据文章id 远程调用feign查询文章
        if (id == null) {
            log.error("文章自动审核失败  文章id为空");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            log.error("文章自动审核失败  未查询自媒体文章信息  id===>  {}", id);
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 2. 判断文章状态是否为待审核状态
        if (!WemediaConstants.WM_NEWS_SUMMIT_STATUS.equals(wmNews.getStatus())) {
            log.error("文章自动审核失败  自媒体文章尚未提交(待审核)  status===>  {}", wmNews.getStatus());
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "自媒体文章尚未提交审核");
        }
        //获取所有图文信息
        Map<String, Object> contentAndImageResult = handleTextAndImages(wmNews);
        String textContent = (String) contentAndImageResult.get("text");
        Object imageContent = contentAndImageResult.get("image");
        // 3.1  敏感词审核    失败   修改文章状态(2)
        boolean isSensivice = handleSensitive(textContent, wmNews);
        if (!isSensivice) return;
        log.info(" 自管理敏感词审核通过  =======   ");
        // 3.2  阿里云的文本审核   失败  状态2  不确定 状态3
        boolean isTextScan = handleTextScan(textContent, wmNews);
        if (!isTextScan) return;
        log.info(" 阿里云内容审核通过  =======   ");
        // 3.3  阿里云的图片审核   失败  状态2  不确定 状态3
        boolean isImageScan = handleImageScan((List<String>) imageContent, wmNews);
        if (!isImageScan) return;
        log.info(" 阿里云图片审核通过  =======   ");
        // 4.审核成功,发布  状态 8
        updateWmNews(wmNews, WemediaConstants.WM_NEWS_AUTHED_STATUS, "审核通过");
        //TODO 5. 通知定时发布文章
        long publishTime = wmNews.getPublishTime().getTime();
        long nowTime = new Date().getTime();
        long remainTime = publishTime - nowTime;
        rabbitTemplate.convertAndSend(PublishArticleConstants.DELAY_DIRECT_EXCHANGE
                , PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY, wmNews.getId(),
                msg -> {
                    msg.getMessageProperties().setHeader("x-delay", remainTime <= 0 ? 0 : remainTime);
                    return msg;
                });
        log.info("文章将在{} 秒后发布~~~", (remainTime / 1000));
    }

    /**
     * 阿里云图片审核
     *
     * @param imageContent
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> imageContent, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(imageContent);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_Fail_STATUS, "图片中有违规内容，审核失败");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_ADMIN_AUTH_STATUS, "图片中有不确定内容，转为人工审核");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云图片审核出现异常 , 原因:{}", e.getMessage());
            updateWmNews(wmNews, WemediaConstants.WM_NEWS_ADMIN_AUTH_STATUS, "阿里云内容服务异常，转为人工审核");
            flag = false;
        }
        return flag;
    }

    /**
     * 阿里云内容审核
     *
     * @param textContent
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String textContent, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(textContent);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_Fail_STATUS, "文本中有违规内容,审核失败");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WemediaConstants.WM_NEWS_LABOR_STATUS, "文本中有不确定内容，转为人工审核");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云文本审核出现异常 , 原因:{}", e.getMessage());
            updateWmNews(wmNews, WemediaConstants.WM_NEWS_LABOR_STATUS, "阿里云内容服务异常，转为人工审核");
            flag = false;
        }
        return flag;
    }

    /**
     * 修改图文状态
     *
     * @param wmNews 图文对象
     * @param status 图文状态
     * @param reason 拒绝理由
     */
    public void updateWmNews(WmNews wmNews, Short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 抽取自媒体文章中所有文本内容及图片路径
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        //获取图文内容
        String content = wmNews.getContent();
        if (StringUtils.isBlank(content)) {
            log.error("自动审核文章失败    文章内容为空");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "文章内容为空");
        }
        List<Map> contentsMap = JSONArray.parseArray(content, Map.class);
        //抽取图文中所有文本信息
        String textStr = contentsMap.stream().filter(e -> e.get("type").equals("text"))
                .map(str -> (String) str.get("value")).collect(Collectors.joining("_hmtt_"));
        textStr = textStr + "_hmtt_" + wmNews.getTitle();
        //抽取图文中的图片路径
        List<String> imageList = contentsMap.stream().filter(e -> e.get("type").equals("image"))
                .map(str -> (String) str.get("value")).distinct().collect(Collectors.toList());
        //取出image中所有图片路径,表中以","分割
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            List<String> urls = Arrays.stream(wmNews.getImages().split(","))
                    .map(url -> webSite + url).distinct().collect(Collectors.toList());
            imageList.addAll(urls);
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("text", textStr);
        map.put("image", imageList);
        return map;
    }

    /**
     * 基于DFA 检测内容是否包含敏感词
     *
     * @param textContent
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String textContent, WmNews wmNews) {
        //调用adminFeign远程接口 查询admin模块中敏感词数据
        ResponseResult<List<String>> result = adminFeign.selectAllSensitive();
        if (!result.checkCode()) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, result.getErrorMessage());
        }
        if (result.getData() == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "查询不到敏感词数据");
        }
        List<String> data = result.getData();
        //将敏感词转化为DFA类型
        SensitiveWordUtil.initMap(data);
        //检测文本信息中的敏感词汇
        Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(textContent);
        if (resultMap != null && resultMap.size() > 0) {
            //文章状态修改为2,审核失败
            updateWmNews(wmNews, WemediaConstants.WM_NEWS_Fail_STATUS, "内容中包含敏感词: " + resultMap);
            log.error("检测到敏感词 {}",resultMap);
            return false;
        }
        return true;
    }
}
